﻿using System;
using System.Collections.Generic;
using System.Data.Common;
using System.Reflection;

namespace MaQiu.SqlExecute.DAL
{
    internal class DbHepler
    {
        public static T ConvertType<T>(object obj)
        {
            if (obj == null || obj == DBNull.Value)
            {
                return default(T);
            }
            if (obj is T)
            {
                return (T)(obj);
            }
            var typeFromHandle = typeof(T);
            return (T)Convert.ChangeType(obj, typeFromHandle);
        }

        public static object ChangeType(object value, Type type)
        {
            return type == typeof(Guid) ? new Guid(value.ToString()) : Convert.ChangeType(value, type);
        }

        private static string[] GetColumnNames(DbDataReader reader)
        {
            var fieldCount = reader.FieldCount;
            var array = new string[fieldCount];
            for (var i = 0; i < fieldCount; i++)
            {
                array[i] = reader.GetName(i);
            }
            return array;
        }

        public static T DataReaderToSingle<T>(DbDataReader reader) where T : class, new()
        {
            var columnNames = GetColumnNames(reader);
            var t = Activator.CreateInstance(typeof(T)) as T;
            if (t == null) return null;
            var type = t.GetType();
            for (var i = 0; i < columnNames.Length; i++)
            {
                var property = type.GetProperty(columnNames[i]);
                var value = reader.GetValue(i);
                if (property == null) { continue; }
                value = value == DBNull.Value ? null : value;
                if (property.PropertyType.IsGenericType &&
                    property.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
                {
                    property.SetValue(t,
                        value == null ? null : ChangeType(value, Nullable.GetUnderlyingType(property.PropertyType)),
                        null);
                }
                else
                {
                    property.SetValue(t, ChangeType(value, property.PropertyType), null);
                }
            }
            return t;
        }

        public static DbParameter[] GetParameters(object param)
        {
            var result = new List<DbParameter>();
            if (param != null)
            {
                var paramList = param as IEnumerable<DbParameter>;
                if (paramList != null)
                {
                    result.AddRange(paramList);
                }
                else
                {
                    var properties = param.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public);
                    foreach (var info in properties)
                    {
                        var value = info.GetValue(param, null);
                        var name = "@" + info.Name;
                        if (value == null || value == DBNull.Value)
                        {
                            result.Add(SqlConnection.Provider.Parameter(name, DBNull.Value));
                        }
                        else
                        {
                            result.Add(SqlConnection.Provider.Parameter(name, value));
                        }
                    }
                }
            }
            else
            {
                return null;
            }
            return result.ToArray();
        }
    }
}